home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
shllutil.lha
/
shellutils-1.8
/
src
/
stty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-28
|
28KB
|
1,242 lines
/* stty -- change and print terminal line settings
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: stty [-ag] [--all] [--save] [setting...]
Options:
-a, --all Write all current settings to stdout in human-readable form.
-g, --save Write all current settings to stdout in stty-readable form.
If no args are given, write to stdout the baud rate and settings that
have been changed from their defaults. Mode reading and changes
are done on stdin.
David MacKenzie <djm@gnu.ai.mit.edu> */
#include <stdio.h>
#include <sys/types.h>
#include <termios.h>
#ifdef _AIX
#include <sys/ioctl.h> /* Needed to get window size. */
#endif
#ifdef WINSIZE_IN_PTEM
#include <sys/stream.h>
#include <sys/ptem.h>
#endif
#include <getopt.h>
#ifdef __STDC__
#include <stdarg.h>
#define VA_START(args, lastarg) va_start(args, lastarg)
#else
#include <varargs.h>
#define VA_START(args, lastarg) va_start(args)
#endif
#include "system.h"
#if defined(GWINSZ_BROKEN) /* Such as for SCO UNIX 3.2.2. */
#undef TIOCGWINSZ
#endif
#ifndef _POSIX_VDISABLE
#define _POSIX_VDISABLE ((unsigned char) 0)
#endif
#define Control(c) ((c) & 0x1f)
/* Canonical values for control characters. */
#ifndef CINTR
#define CINTR Control ('c')
#endif
#ifndef CQUIT
#define CQUIT 28
#endif
#ifndef CERASE
#define CERASE 127
#endif
#ifndef CKILL
#define CKILL Control ('u')
#endif
#ifndef CEOF
#define CEOF Control ('d')
#endif
#ifndef CEOL
#define CEOL _POSIX_VDISABLE
#endif
#ifndef CSTART
#define CSTART Control ('q')
#endif
#ifndef CSTOP
#define CSTOP Control ('s')
#endif
#ifndef CSUSP
#define CSUSP Control ('z')
#endif
#if defined(VEOL2) && !defined(CEOL2)
#define CEOL2 _POSIX_VDISABLE
#endif
#if defined(VSWTCH) && !defined(CSWTCH)
#define CSWTCH _POSIX_VDISABLE
#endif
#if defined(VDSUSP) && !defined (CDSUSP)
#define CDSUSP Control ('y')
#endif
#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
#define VREPRINT VRPRNT
#endif
#if defined(VREPRINT) && !defined(CRPRNT)
#define CRPRNT Control ('r')
#endif
#if defined(VWERASE) && !defined(CWERASE)
#define CWERASE Control ('w')
#endif
#if defined(VLNEXT) && !defined(CLNEXT)
#define CLNEXT Control ('v')
#endif
char *visible ();
unsigned long baud_to_value ();
int recover_mode ();
int screen_columns ();
int set_mode ();
long integer_arg ();
speed_t string_to_baud ();
tcflag_t *mode_type_flag ();
void display_all ();
void display_changed ();
void display_recoverable ();
void display_settings ();
void display_speed ();
void display_window_size ();
void error ();
void sane_mode ();
void set_control_char ();
void set_speed ();
void set_window_size ();
/* Which speeds to set. */
enum speed_setting
{
input_speed, output_speed, both_speeds
};
/* What to output and how. */
enum output_type
{
changed, all, recoverable /* Default, -a, -g. */
};
/* Which member(s) of `struct termios' a mode uses. */
enum mode_type
{
control, input, output, local, combination
};
/* Flags for `struct mode_info'. */
#define SANE_SET 1 /* Set in `sane' mode. */
#define SANE_UNSET 2 /* Unset in `sane' mode. */
#define REV 4 /* Can be turned off by prepending `-'. */
#define OMIT 8 /* Don't display value. */
/* Each mode. */
struct mode_info
{
char *name; /* Name given on command line. */
enum mode_type type; /* Which structure element to change. */
char flags; /* Setting and display options. */
unsigned long bits; /* Bits to set for this mode. */
unsigned long mask; /* Other bits to turn off for this mode. */
};
struct mode_info mode_info[] =
{
{"parenb", control, REV, PARENB, 0},
{"parodd", control, REV, PARODD, 0},
{"cs5", control, 0, CS5, CSIZE},
{"cs6", control, 0, CS6, CSIZE},
{"cs7", control, 0, CS7, CSIZE},
{"cs8", control, 0, CS8, CSIZE},
{"hupcl", control, REV, HUPCL, 0},
{"hup", control, REV | OMIT, HUPCL, 0},
{"cstopb", control, REV, CSTOPB, 0},
{"cread", control, SANE_SET | REV, CREAD, 0},
{"clocal", control, REV, CLOCAL, 0},
#ifdef CRTSCTS
{"crtscts", control, REV, CRTSCTS, 0},
#endif
{"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
{"brkint", input, SANE_SET | REV, BRKINT, 0},
{"ignpar", input, REV, IGNPAR, 0},
{"parmrk", input, REV, PARMRK, 0},
{"inpck", input, REV, INPCK, 0},
{"istrip", input, REV, ISTRIP, 0},
{"inlcr", input, SANE_UNSET | REV, INLCR, 0},
{"igncr", input, SANE_UNSET | REV, IGNCR, 0},
{"icrnl", input, SANE_SET | REV, ICRNL, 0},
{"ixon", input, REV, IXON, 0},
{"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
{"tandem", input, REV | OMIT, IXOFF, 0},
#ifdef IUCLC
{"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
#endif
#ifdef IXANY
{"ixany", input, SANE_UNSET | REV, IXANY, 0},
#endif
#ifdef IMAXBEL
{"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
#endif
{"opost", output, SANE_SET | REV, OPOST, 0},
#ifdef OLCUC
{"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
#endif
#ifdef OCRNL
{"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
#endif
#ifdef ONLCR
{"onlcr", output, SANE_SET | REV, ONLCR, 0},
#endif
#ifdef ONOCR
{"onocr", output, SANE_UNSET | REV, ONOCR, 0},
#endif
#ifdef ONLRET
{"onlret", output, SANE_UNSET | REV, ONLRET, 0},
#endif
#ifdef OFILL
{"ofill", output, SANE_UNSET | REV, OFILL, 0},
#endif
#ifdef OFDEL
{"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
#endif
#ifdef NLDLY
{"nl1", output, SANE_UNSET, NL1, NLDLY},
{"nl0", output, SANE_SET, NL0, NLDLY},
#endif
#ifdef CRDLY
{"cr3", output, SANE_UNSET, CR3, CRDLY},
{"cr2", output, SANE_UNSET, CR2, CRDLY},
{"cr1", output, SANE_UNSET, CR1, CRDLY},
{"cr0", output, SANE_SET, CR0, CRDLY},
#endif
#ifdef TABDLY
{"tab3", output, SANE_UNSET, TAB3, TABDLY},
{"tab2", output, SANE_UNSET, TAB2, TABDLY},
{"tab1", output, SANE_UNSET, TAB1, TABDLY},
{"tab0", output, SANE_SET, TAB0, TABDLY},
#endif
#ifdef BSDLY
{"bs1", output, SANE_UNSET, BS1, BSDLY},
{"bs0", output, SANE_SET, BS0, BSDLY},
#endif
#ifdef VTDLY
{"vt1", output, SANE_UNSET, VT1, VTDLY},
{"vt0", output, SANE_SET, VT0, VTDLY},
#endif
#ifdef FFDLY
{"ff1", output, SANE_UNSET, FF1, FFDLY},
{"ff0", output, SANE_SET, FF0, FFDLY},
#endif
{"isig", local, SANE_SET | REV, ISIG, 0},
{"icanon", local, SANE_SET | REV, ICANON, 0},
#ifdef IEXTEN
{"iexten", local, SANE_SET | REV, IEXTEN, 0},
#endif
{"echo", local, SANE_SET | REV, ECHO, 0},
{"echoe", local, SANE_SET | REV, ECHOE, 0},
{"crterase", local, REV | OMIT, ECHOE, 0},
{"echok", local, SANE_SET | REV, ECHOK, 0},
{"echonl", local, SANE_UNSET | REV, ECHONL, 0},
{"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
#ifdef XCASE
{"xcase", local, SANE_UNSET | REV, XCASE, 0},
#endif
#ifdef TOSTOP
{"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
#endif
#ifdef ECHOPRT
{"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
{"prterase", local, REV | OMIT, ECHOPRT, 0},
#endif
#ifdef ECHOCTL
{"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
{"ctlecho", local, REV | OMIT, ECHOCTL, 0},
#endif
#ifdef ECHOKE
{"echoke", local, SANE_SET | REV, ECHOKE, 0},
{"crtkill", local, REV | OMIT, ECHOKE, 0},
#endif
{"evenp", combination, REV | OMIT, 0, 0},
{"parity", combination, REV | OMIT, 0, 0},
{"oddp", combination, REV | OMIT, 0, 0},
{"nl", combination, REV | OMIT, 0, 0},
{"ek", combination, OMIT, 0, 0},
{"sane", combination, OMIT, 0, 0},
{"cooked", combination, REV | OMIT, 0, 0},
{"raw", combination, REV | OMIT, 0, 0},
{"pass8", combination, REV | OMIT, 0, 0},
{"litout", combination, REV | OMIT, 0, 0},
{"cbreak", combination, REV | OMIT, 0, 0},
#ifdef IXANY
{"decctlq", combination, REV | OMIT, 0, 0},
#endif
#ifdef TABDLY
{"tabs", combination, REV | OMIT, 0, 0},
#endif
#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
{"lcase", combination, REV | OMIT, 0, 0},
{"LCASE", combination, REV | OMIT, 0, 0},
#endif
{"crt", combination, OMIT, 0, 0},
{"dec", combination, OMIT, 0, 0},
{NULL, control, 0, 0, 0}
};
/* Control character settings. */
struct control_info
{
char *name; /* Name given on command line. */
unsigned char saneval; /* Value to set for `stty sane'. */
int offset; /* Offset in c_cc. */
};
/* Control characters. */
struct control_info control_info[] =
{
{"intr", CINTR, VINTR},
{"quit", CQUIT, VQUIT},
{"erase", CERASE, VERASE},
{"kill", CKILL, VKILL},
{"eof", CEOF, VEOF},
{"eol", CEOL, VEOL},
#ifdef VEOL2
{"eol2", CEOL2, VEOL2},
#endif
#ifdef VSWTCH
{"swtch", CSWTCH, VSWTCH},
#endif
{"start", CSTART, VSTART},
{"stop", CSTOP, VSTOP},
{"susp", CSUSP, VSUSP},
#ifdef VDSUSP
{"dsusp", CDSUSP, VDSUSP},
#endif
#ifdef VREPRINT
{"rprnt", CRPRNT, VREPRINT},
#endif
#ifdef VWERASE
{"werase", CWERASE, VWERASE},
#endif
#ifdef VLNEXT
{"lnext", CLNEXT, VLNEXT},
#endif
/* These must be last because of the display routines. */
{"min", 1, VMIN},
{"time", 0, VTIME},
{NULL, 0, 0}
};
/* The width of the screen, for output wrapping. */
int max_col;
/* Current position, to know when to wrap. */
int current_col;
struct option longopts[] =
{
{"all", 0, NULL, 'a'},
{"save", 0, NULL, 'g'},
{NULL, 0, NULL, 0}
};
/* The name this program was run with. */
char *program_name;
/* Print format string MESSAGE and optional args.
Wrap to next line first if it won't fit.
Print a space first unless MESSAGE will start a new line. */
/* VARARGS */
void
#ifdef __STDC__
wrapf (char *message, ...)
#else
wrapf (message, va_alist)
char *message;
va_dcl
#endif
{
va_list args;
char buf[1024]; /* Plenty long for our needs. */
int buflen;
VA_START (args, message);
vsprintf (buf, message, args);
va_end (args);
buflen = strlen (buf);
if (current_col + buflen >= max_col)
{
putchar ('\n');
current_col = 0;
}
if (current_col > 0)
{
putchar (' ');
current_col++;
}
fputs (buf, stdout);
current_col += buflen;
}
void
main (argc, argv)
int argc;
char **argv;
{
struct termios mode;
enum output_type output_type = changed;
int optc;
program_name = argv[0];
opterr = 0;
while ((optc = getopt_long (argc, argv, "ag", longopts, (int *) 0)) != EOF)
{
if (optc == 'a')
output_type = all;
else if (optc == 'g')
output_type = recoverable;
else
break;
}
if (tcgetattr (0, &mode))
error (1, errno, "standard input");
max_col = screen_columns ();
current_col = 0;
if (optind == argc)
{
if (optc == '?')
error (1, 0, "invalid argument `%s'", argv[--optind]);
display_settings (output_type, &mode);
exit (0);
}
while (optind < argc)
{
int match_found = 0;
int reversed = 0;
int i;
if (argv[optind][0] == '-')
{
++argv[optind];
reversed = 1;
}
for (i = 0; mode_info[i].name != NULL; ++i)
{
if (!strcmp (argv[optind], mode_info[i].name))
{
match_found = set_mode (&mode_info[i], reversed, &mode);
break;
}
}
if (match_found == 0 && reversed)
error (1, 0, "invalid argument `%s'", --argv[optind]);
if (match_found == 0)
{
for (i = 0; control_info[i].name != NULL; ++i)
{
if (!strcmp (argv[optind], control_info[i].name))
{
if (optind == argc - 1)
error (1, 0, "missing argument to `%s'", argv[optind]);
match_found = 1;
++optind;
set_control_char (&control_info[i], argv[optind], &mode);
break;
}
}
}
if (match_found == 0)
{
if (!strcmp (argv[optind], "ispeed"))
{
if (optind == argc - 1)
error (1, 0, "missing argument to `%s'", argv[optind]);
++optind;
set_speed (input_speed, argv[optind], &mode);
}
else if (!strcmp (argv[optind], "ospeed"))
{
if (optind == argc - 1)
error (1, 0, "missing argument to `%s'", argv[optind]);
++optind;
set_speed (output_speed, argv[optind], &mode);
}
#ifdef TIOCGWINSZ
else if (!strcmp (argv[optind], "rows"))
{
if (optind == argc - 1)
error (1, 0, "missing argument to `%s'", argv[optind]);
++optind;
set_window_size ((int) integer_arg (argv[optind]), -1);
}
else if (!strcmp (argv[optind], "cols")
|| !strcmp (argv[optind], "columns"))
{
if (optind == argc - 1)
error (1, 0, "missing argument to `%s'", argv[optind]);
++optind;
set_window_size (-1, (int) integer_arg (argv[optind]));
}
else if (!strcmp (argv[optind], "size"))
display_window_size (0);
#endif
#ifdef HAVE_C_LINE
else if (!strcmp (argv[optind], "line"))
{
if (optind == argc - 1)
error (1, 0, "missing argument to `%s'", argv[optind]);
++optind;
mode.c_line = integer_arg (argv[optind]);
}
#endif
else if (!strcmp (argv[optind], "speed"))
display_speed (&mode, 0);
else if (string_to_baud (argv[optind]) != (speed_t) -1)
set_speed (both_speeds, argv[optind], &mode);
else if (recover_mode (argv[optind], &mode) == 0)
error (1, 0, "invalid argument `%s'", argv[optind]);
}
optind++;
}
if (tcsetattr (0, TCSADRAIN, &mode))
error (1, errno, "standard input");
exit (0);
}
/* Return 0 if not applied because not reversible; otherwise return 1. */
int
set_mode (info, reversed, mode)
struct mode_info *info;
int reversed;
struct termios *mode;
{
tcflag_t *bitsp;
if (reversed && (info->flags & REV) == 0)
return 0;
bitsp = mode_type_flag (info->type, mode);
if (bitsp == NULL)
{
/* Combination mode. */
if (!strcmp (info->name, "evenp") || !strcmp (info->name, "parity"))
{
if (reversed)
mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
else
mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
}
else if (!strcmp (info->name, "oddp"))
{
if (reversed)
mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
else
mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
}
else if (!strcmp (info->name, "nl"))
{
if (reversed)
{
mode->c_iflag = mode->c_iflag | ICRNL & ~INLCR & ~IGNCR;
mode->c_oflag = mode->c_oflag
#ifdef ONLCR
| ONLCR
#endif
#ifdef OCRNL
& ~OCRNL
#endif
#ifdef ONLRET
& ~ONLRET
#endif
;
}
else
{
mode->c_iflag = mode->c_iflag & ~ICRNL;
#ifdef ONLCR
mode->c_oflag = mode->c_oflag & ~ONLCR;
#endif
}
}
else if (!strcmp (info->name, "ek"))
{
mode->c_cc[VERASE] = CERASE;
mode->c_cc[VKILL] = CKILL;
}
else if (!strcmp (info->name, "sane"))
sane_mode (mode);
else if (!strcmp (info->name, "cbreak"))
{
if (reversed)
mode->c_lflag |= ICANON;
else
mode->c_lflag &= ~ICANON;
}
else if (!strcmp (info->name, "pass8"))
{
if (reversed)
{
mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
mode->c_iflag |= ISTRIP;
}
else
{
mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
mode->c_iflag &= ~ISTRIP;
}
}
else if (!strcmp (info->name, "litout"))
{
if (reversed)
{
mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
mode->c_iflag |= ISTRIP;
mode->c_oflag |= OPOST;
}
else
{
mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
mode->c_iflag &= ~ISTRIP;
mode->c_oflag &= ~OPOST;
}
}
else if (!strcmp (info->name, "raw") || !strcmp (info->name, "cooked"))
{
if ((info->name[0] == 'r' && reversed)
|| (info->name[0] == 'c' && !reversed))
{
/* Cooked mode. */
mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
mode->c_oflag |= OPOST;
mode->c_lflag |= ISIG | ICANON;
#if VMIN == VEOF
mode->c_cc[VEOF] = CEOF;
#endif
#if VTIME == VEOL
mode->c_cc[VEOL] = CEOL;
#endif
}
else
{
/* Raw mode. */
mode->c_iflag = 0;
mode->c_oflag &= ~OPOST;
mode->c_lflag &= ~(ISIG | ICANON
#ifdef XCASE
| XCASE
#endif
);
mode->c_cc[VMIN] = 1;
mode->c_cc[VTIME] = 0;
}
}
#ifdef IXANY
else if (!strcmp (info->name, "decctlq"))
{
if (reversed)
mode->c_iflag |= IXANY;
else
mode->c_iflag &= ~IXANY;
}
#endif
#ifdef TABDLY
else if (!strcmp (info->name, "tabs"))
{
if (reversed)
mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
else
mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
}
#endif
#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
else if (!strcmp (info->name, "lcase")
|| !strcmp (info->name, "LCASE"))
{
if (reversed)
{
mode->c_lflag &= ~XCASE;
mode->c_iflag &= ~IUCLC;
mode->c_oflag &= ~OLCUC;
}
else
{
mode->c_lflag |= XCASE;
mode->c_iflag |= IUCLC;
mode->c_oflag |= OLCUC;
}
}
#endif
else if (!strcmp (info->name, "crt"))
mode->c_lflag |= ECHOE
#ifdef ECHOCTL
| ECHOCTL
#endif
#ifdef ECHOKE
| ECHOKE
#endif
;
else if (!strcmp (info->name, "dec"))
{
mode->c_cc[VINTR] = 3; /* ^C */
mode->c_cc[VERASE] = 127; /* DEL */
mode->c_cc[VKILL] = 21; /* ^U */
mode->c_lflag |= ECHOE
#ifdef ECHOCTL
| ECHOCTL
#endif
#ifdef ECHOKE
| ECHOKE
#endif
;
#ifdef IXANY
mode->c_iflag &= ~IXANY;
#endif
}
}
else if (reversed)
*bitsp = *bitsp & ~info->mask & ~info->bits;
else
*bitsp = (*bitsp & ~info->mask) | info->bits;
return 1;
}
void
set_control_char (info, arg, mode)
struct control_info *info;
char *arg;
struct termios *mode;
{
unsigned char value;
if (!strcmp (info->name, "min") || !strcmp (info->name, "time"))
value = integer_arg (arg);
else if (arg[0] == '\0' || arg[1] == '\0')
value = arg[0];
else if (!strcmp (arg, "^-") || !strcmp (arg, "undef"))
value = _POSIX_VDISABLE;
else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
{
if (arg[1] == '?')
value = 127;
else
value = arg[1] & ~0140; /* Non-letters get weird results. */
}
else
value = integer_arg (arg);
mode->c_cc[info->offset] = value;
}
void
set_speed (type, arg, mode)
enum speed_setting type;
char *arg;
struct termios *mode;
{
speed_t baud;
baud = string_to_baud (arg);
if (type == input_speed || type == both_speeds)
cfsetispeed (mode, baud);
if (type == output_speed || type == both_speeds)
cfsetospeed (mode, baud);
}
#ifdef TIOCGWINSZ
void
set_window_size (rows, cols)
int rows, cols;
{
struct winsize win;
if (ioctl (0, TIOCGWINSZ, (char *) &win))
error (1, errno, "standard input");
if (rows >= 0)
win.ws_row = rows;
if (cols >= 0)
win.ws_col = cols;
if (ioctl (0, TIOCSWINSZ, (char *) &win))
error (1, errno, "standard input");
}
void
display_window_size (fancy)
int fancy;
{
struct winsize win;
if (ioctl (0, TIOCGWINSZ, (char *) &win))
error (1, errno, "standard input");
wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n", win.ws_row, win.ws_col);
if (!fancy)
current_col = 0;
}
#endif
int
screen_columns ()
{
#ifdef TIOCGWINSZ
struct winsize win;
if (ioctl (0, TIOCGWINSZ, (char *) &win))
error (1, errno, "standard input");
if (win.ws_col > 0)
return win.ws_col;
#endif
if (getenv ("COLUMNS"))
return atoi (getenv ("COLUMNS"));
return 80;
}
tcflag_t *
mode_type_flag (type, mode)
enum mode_type type;
struct termios *mode;
{
switch (type)
{
case control:
return &mode->c_cflag;
case input:
return &mode->c_iflag;
case output:
return &mode->c_oflag;
case local:
return &mode->c_lflag;
case combination:
return NULL;
}
}
void
display_settings (output_type, mode)
enum output_type output_type;
struct termios *mode;
{
switch (output_type)
{
case changed:
display_changed (mode);
break;
case all:
display_all (mode);
break;
case recoverable:
display_recoverable (mode);
break;
}
}
void
display_changed (mode)
struct termios *mode;
{
int i;
int empty_line;
tcflag_t *bitsp;
unsigned long mask;
enum mode_type prev_type = control;
display_speed (mode, 1);
#ifdef HAVE_C_LINE
wrapf ("line = %d;", mode->c_line);
#endif
putchar ('\n');
current_col = 0;
empty_line = 1;
for (i = 0; strcmp (control_info[i].name, "min"); ++i)
{
if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
continue;
empty_line = 0;
wrapf ("%s = %s;", control_info[i].name,
visible (mode->c_cc[control_info[i].offset]));
}
if ((mode->c_lflag & ICANON) == 0)
{
wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
(int) mode->c_cc[VTIME]);
}
else if (empty_line == 0)
putchar ('\n');
current_col = 0;
empty_line = 1;
for (i = 0; mode_info[i].name != NULL; ++i)
{
if (mode_info[i].flags & OMIT)
continue;
if (mode_info[i].type != prev_type)
{
if (empty_line == 0)
{
putchar ('\n');
current_col = 0;
empty_line = 1;
}
prev_type = mode_info[i].type;
}
bitsp = mode_type_flag (mode_info[i].type, mode);
mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
if ((*bitsp & mask) == mode_info[i].bits)
{
if (mode_info[i].flags & SANE_UNSET)
{
wrapf ("%s", mode_info[i].name);
empty_line = 0;
}
}
else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
{
wrapf ("-%s", mode_info[i].name);
empty_line = 0;
}
}
if (empty_line == 0)
putchar ('\n');
current_col = 0;
}
void
display_all (mode)
struct termios *mode;
{
int i;
tcflag_t *bitsp;
unsigned long mask;
enum mode_type prev_type = control;
display_speed (mode, 1);
#ifdef TIOCGWINSZ
display_window_size (1);
#endif
#ifdef HAVE_C_LINE
wrapf ("line = %d;", mode->c_line);
#endif
putchar ('\n');
current_col = 0;
for (i = 0; strcmp (control_info[i].name, "min"); ++i)
{
wrapf ("%s = %s;", control_info[i].name,
visible (mode->c_cc[control_info[i].offset]));
}
wrapf ("min = %d; time = %d;\n", mode->c_cc[VMIN], mode->c_cc[VTIME]);
current_col = 0;
for (i = 0; mode_info[i].name != NULL; ++i)
{
if (mode_info[i].flags & OMIT)
continue;
if (mode_info[i].type != prev_type)
{
putchar ('\n');
current_col = 0;
prev_type = mode_info[i].type;
}
bitsp = mode_type_flag (mode_info[i].type, mode);
mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
if ((*bitsp & mask) == mode_info[i].bits)
wrapf ("%s", mode_info[i].name);
else if (mode_info[i].flags & REV)
wrapf ("-%s", mode_info[i].name);
}
putchar ('\n');
current_col = 0;
}
void
display_speed (mode, fancy)
struct termios *mode;
int fancy;
{
if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
wrapf (fancy ? "speed %lu baud;" : "%lu\n",
baud_to_value (cfgetospeed (mode)));
else
wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
baud_to_value (cfgetispeed (mode)),
baud_to_value (cfgetospeed (mode)));
if (!fancy)
current_col = 0;
}
void
display_recoverable (mode)
struct termios *mode;
{
int i;
printf ("%lx:%lx:%lx:%lx",
(unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
(unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
for (i = 0; i < NCCS; ++i)
printf (":%x", (unsigned int) mode->c_cc[i]);
putchar ('\n');
}
int
recover_mode (arg, mode)
char *arg;
struct termios *mode;
{
int i, n;
unsigned int chr;
unsigned long iflag, oflag, cflag, lflag;
/* Scan into temporaries since it is too much trouble to figure out
the right format for `tcflag_t'. */
if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
&iflag, &oflag, &cflag, &lflag, &n) != 4)
return 0;
mode->c_iflag = iflag;
mode->c_oflag = oflag;
mode->c_cflag = cflag;
mode->c_lflag = lflag;
arg += n;
for (i = 0; i < NCCS; ++i)
{
if (sscanf (arg, ":%x%n", &chr, &n) != 1)
return 0;
mode->c_cc[i] = chr;
arg += n;
}
return 1;
}
struct speed_map
{
char *string; /* ASCII representation. */
speed_t speed; /* Internal form. */
unsigned long value; /* Numeric value. */
};
struct speed_map speeds[] =
{
{"0", B0, 0},
{"50", B50, 50},
{"75", B75, 75},
{"110", B110, 110},
{"134", B134, 134},
{"134.5", B134, 134},
{"150", B150, 150},
{"200", B200, 200},
{"300", B300, 300},
{"600", B600, 600},
{"1200", B1200, 1200},
{"1800", B1800, 1800},
{"2400", B2400, 2400},
{"4800", B4800, 4800},
{"9600", B9600, 9600},
{"19200", B19200, 19200},
{"38400", B38400, 38400},
{"exta", B19200, 19200},
{"extb", B38400, 38400},
#ifdef B57600
{"57600", B57600, 57600},
#endif
#ifdef B115200
{"115200", B115200, 115200},
#endif
{NULL, 0, 0}
};
speed_t
string_to_baud (arg)
char *arg;
{
int i;
for (i = 0; speeds[i].string != NULL; ++i)
if (!strcmp (arg, speeds[i].string))
return speeds[i].speed;
return (speed_t) -1;
}
unsigned long
baud_to_value (speed)
speed_t speed;
{
int i;
for (i = 0; speeds[i].string != NULL; ++i)
if (speed == speeds[i].speed)
return speeds[i].value;
return 0;
}
void
sane_mode (mode)
struct termios *mode;
{
int i;
tcflag_t *bitsp;
for (i = 0; control_info[i].name; ++i)
{
#if VMIN == VEOF
if (!strcmp (control_info[i].name, "min"))
break;
#endif
mode->c_cc[control_info[i].offset] = control_info[i].saneval;
}
for (i = 0; mode_info[i].name != NULL; ++i)
{
if (mode_info[i].flags & SANE_SET)
{
bitsp = mode_type_flag (mode_info[i].type, mode);
*bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
}
else if (mode_info[i].flags & SANE_UNSET)
{
bitsp = mode_type_flag (mode_info[i].type, mode);
*bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
}
}
}
/* Return a string that is the printable representation of character CH. */
/* Adapted from `cat' by Torbjorn Granlund. */
char *
visible (ch)
unsigned char ch;
{
static char buf[10];
char *bpout = buf;
if (ch == _POSIX_VDISABLE)
return "<undef>";
if (ch >= 32)
{
if (ch < 127)
*bpout++ = ch;
else if (ch == 127)
{
*bpout++ = '^';
*bpout++ = '?';
}
else
{
*bpout++ = 'M',
*bpout++ = '-';
if (ch >= 128 + 32)
{
if (ch < 128 + 127)
*bpout++ = ch - 128;
else
{
*bpout++ = '^';
*bpout++ = '?';
}
}
else
{
*bpout++ = '^';
*bpout++ = ch - 128 + 64;
}
}
}
else
{
*bpout++ = '^';
*bpout++ = ch + 64;
}
*bpout = '\0';
return buf;
}
/* Parse string S as an integer, using decimal radix by default,
but allowing octal and hex numbers as in C. */
/* From `od' by Richard Stallman. */
long
integer_arg (s)
char *s;
{
long value;
int radix = 10;
char *p = s;
int c;
if (*p != '0')
radix = 10;
else if (*++p == 'x')
{
radix = 16;
p++;
}
else
radix = 8;
value = 0;
while (((c = *p++) >= '0' && c <= '9')
|| (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
{
value *= radix;
if (c >= '0' && c <= '9')
value += c - '0';
else
value += (c & ~40) - 'A';
}
if (c == 'b')
value *= 512;
else if (c == 'B')
value *= 1024;
else
p--;
if (*p)
error (1, 0, "invalid integer argument `%s'", s);
return value;
}